

#ifndef __ALGO_RC4_H_
#define __ALGO_RC4_H_
////////////////////////////////////////////////////////////////////////////////
namespace rc4{ //namespace rc4 begin.
////////////////////////////////////////////////////////////////////////////////
class encoder{
    unsigned char s[256];
    unsigned int i, j, k;
public:
    inline encoder(const void *key, size_t bytes){
        reset(key, bytes);
    }
    inline encoder(){
        reset("374315ed9864f687d6d5144167944eb8", 32);
    }
    inline void reset(const void *key, size_t bytes){
        unsigned char *p = (unsigned char*)key;
        for (k = 0, i = 1; i < bytes; i++){
            k += (p[i] + p[i - 1]) % sizeof(s);
        }
        unsigned char c[sizeof(s)];
        for (i = 0; i < sizeof(s); i++){
            s[i] = i;
            c[i] = p[i % bytes] ^ rand_c();
        }
        for (i = 0, j = 0; i < sizeof(s); i++){
            j = (j + s[i] + c[i]) % sizeof(s);
            switch_c(i, j);
        }
        i = j = 0;
    }
    inline void convert(const void *in, size_t bytes, void *out){
        unsigned char *p = (unsigned char*)in;
        unsigned char *v = (unsigned char*)out;
        for (size_t n = 0; n < bytes; n++){
            i = (i + 1) % sizeof(s);
            j = (j + s[i]) % sizeof(s);
            switch_c(i, j);
            v[n] = p[n] ^ s[(s[i] + s[j]) % sizeof(s)];
        }
    }
private:
    inline void switch_c(int a, int b){
        unsigned char c = s[a];
        s[a] = s[b];
        s[b] = c;
    }
    inline unsigned char rand_c(){
        k = ((k * 0x343fd + 0x269ec3) >> 16) & 0x7fff;
        return (unsigned char)(k % sizeof(s));
    }
};
////////////////////////////////////////////////////////////////////////////////
} //end of namespace rc4.
////////////////////////////////////////////////////////////////////////////////
#endif //__ALGO_RC4_H_
